package liming.tool.handle.net.udp2.socket;

import liming.tool.handle.ReceiveMap;
import liming.tool.handle.net.root.NetReceiveMap;
import liming.tool.handle.net.root.RootSocket;
import liming.tool.handle.net.udp2.base.UdpBaseMethod;

import java.net.DatagramPacket;
import java.net.InetAddress;
import java.util.Arrays;

/**
 * 作为UDP方向总类，规定基础方法与工具类，方便分化后使用
 * 在udp中，需要考虑数据有效性，与丢包情况，在客户端中，尽可能使用一次连接模式，及向服务器端发送数据后，在收到服务器处理的数据后就关闭连接
 * 在服务器端，采用异步发送与接收，在客户端中，采用同步
 * 核心：发送与接收，数据合并功能，重传机制
 * 发送：将ReceiveMap转为多个NetTemp包并加入到发送队列中（记录ReceiveMap的ID），也可直接将NetTemp包加入到队列中（不记录ID），由发送队列异步发送（不阻塞主线程），并将其放入发送超时缓存队列中等待重发或取消
 * 接收：将收到的DatagramPacket放入receive缓存队列中（不阻塞其他线程）
 */
public abstract class UdpSocket extends RootSocket implements UdpBaseMethod {

    private final long PACKET_NUM = 0;//累计发送计数
    private final int PACKET_SIZE = 32 * 1024;//接收发送缓冲区大小

    /**
     * 默认构造函数，在网络通信中，套接字信息都是一个必要的参数
     *
     * @param inetAddress
     * @param port
     */
    public UdpSocket(InetAddress inetAddress, int port) {
        super(inetAddress, port);
    }

    public static void read(DatagramPacket datagramPacket) {
        int length = datagramPacket.getLength();
        byte[] data = datagramPacket.getData();
        if (data.length >= 100 && Byte.valueOf(data[0]).intValue() == 0) {

        }

    }

    public static byte[] write(NetReceiveMap netReceiveMap, int num, int size) {
        byte[] head = new byte[90];
        head[0] = 0x00;//设置标头 0
        setVersion(head, netReceiveMap.getVersion());//设置版本 1-3
        setDataSize(head, size);//设置自己缓冲区大小
        byte[] id = setId(head, getBytes(netReceiveMap.getBytesID(44), ReceiveMap.UUID.getBytes()));

        return id;
    }

    private static byte[] getBytes(byte[] bs, byte[]... bss) {
        int length = bs.length;
        for (byte[] bytes : bss)
            length += bytes.length;
//        System.out.println(length);
        byte[] bytes = new byte[length];
        int index = putByte(bytes, bs, 0);
        for (byte[] b : bss)
            index = putByte(bytes, b, index);
        return bytes;
    }

    private static int putByte(byte[] bytes, byte[] value, int index) {
        System.out.println(index + " " + value.length + " " + Arrays.toString(value));
        for (byte b : value)
            bytes[index++] = (byte) (b < 0 ? b + 128 : b);
//            bytes[index++] = b;
        return index;
    }

    private static void setVersion(byte[] bs, byte[] version) {
        bs[1] = version[0];
        bs[2] = version[1];
        bs[3] = version[2];
    }

    private static void setDataSize(byte[] bs, int size) {
        if (size < 100 || size > 65535)
            throw new RuntimeException("Size must be between 100 and 65535");
        bs[3] = (byte) (size >>> 8 & 0xff);
        bs[4] = (byte) (size & 0xff);
    }

    private static byte[] setId(byte[] bs, byte[] id) {
        int index = 6;
        while (index < 86)
            bs[index] = id[(index++) - 6];
        return id;
    }


    public static void main(String[] args) {
//        byte[] id = new NetReceiveMap().getBytesID(28);//80-16-36=28
//        byte[] time=ByteBuffer.allocate(8).putLong(System.currentTimeMillis()).array();//8
//        byte[] num=ByteBuffer.allocate(8).putLong(PACKET_NUM+10).array();//8
//        byte[] UUID = ReceiveMap.UUID.getBytes();//36
//        System.out.println(Arrays.toString(getBytes(id,time,num,UUID)));
//        byte[] write = write(new NetReceiveMap());
//        System.out.println(write);
        for (int i = 0; i < 128; i++) {
            System.out.println("i: " + i + " " + (char) i);
        }
        char c = 0x5c;
        System.out.println(c + " " + (int) c);
    }
}
